// 十、高级类型（下）

// 1.this类型

class Counters {
  constructor(public count: number = 0) {}
  public add(value: number) {
    this.count += value;
    return this;
  }
  public subtract(value: number) {
    this.count -= value;
    return this;
  }
}

let counter1 = new Counters(10);
// console.log(counter1.add(3).subtract(2));

class PowCounter extends Counters {
  constructor(public count: number = 0) {
    super(count);
  }
  public pow(value: number) {
    this.count = this.count ** value;
    return this;
  }
}
let powCounter = new PowCounter(2);
// console.log(powCounter.pow(3).subtract(3));

// 2.索引类型

// 2.1索引类型查询操作符 keyof ：连接一个类型，返回一个由这个类型的所有属性名组成的联合类型

interface InfoInterfaceAdvanced {
  name: string;
  age: number;
}
let infoProp: keyof InfoInterfaceAdvanced;
infoProp = 'name';
infoProp = 'age';
// infoProp = 'sex'

function getValue<T, K extends keyof T>(obj: T, names: K[]): T[K][] {
  return names.map((n) => obj[n]);
}
const infoObj = {
  name: 'lp',
  age: 18,
};
let infoValues: (string | number)[] = getValue(infoObj, ['name', 'age']);
// console.log(infoValues);

// 2.2索引访问操作符 []

type NameTypes = InfoInterfaceAdvanced['name'];

function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
  return o[name];
}

interface Objs<T> {
  [key: string]: T;
}
// let keys :keyof Objs<number>
const objs1: Objs<number> = {
  age: 18,
};
let keys: Objs<number>['name'];

interface Type {
  a: never;
  b: never;
  c: string;
  d: number;
  e: undefined;
  f: null;
  g: object;
}

type Test = Type[keyof Type]; //keyof Type 返回类型不为never undefined null 的属性名

// 3.映射类型

// 3.1基础

// TS提供了借助旧类型创建新类型方式=>映射类型，他可以相同的形式转换旧类型中每一个属性

interface Info1 {
  age: number;
  name: string;
  sex: string;
}
// interface ReadonlyType {
// readonly age: number
//   readonly name: string,
//   readonly sex: string
// }
type ReadonlyType<T> = {
  +readonly [P in keyof T]?: T[P];
};
type ReadonlyInfo1 = ReadonlyType<Info1>;
let info11: ReadonlyInfo1 = {
  age: 18,
  name: 'lp',
  // sex: 'man'
};
type RemoveReadonlyInfo2<T> = {
  -readonly [P in keyof T]-?: T[P];
};
type InfoWithoutReadonlt = RemoveReadonlyInfo2<ReadonlyInfo1>;

// info11.age = 20

// TS 内置映射类型 Readonly：只读   Partial：可选  Pick：部分  Record：某一些属性转换为其他值

// Pick 实现：
// type Pick<T,K extends keyof T> = {
//   [P in K] : T[P]
// }

interface Info2 {
  name: string;
  age: number;
  address: string;
}
const info3: Info2 = {
  name: 'lp',
  age: 18,
  address: 'beijing',
};
function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
  let res: any = {};
  keys.map((key) => {
    res[key] = obj[key];
  });
  return res;
}
const nameAndAddress = pick(info3, ['name', 'address']);
// console.log(nameAndAddress);

// Record 实现：
// type Record<K extends keyof any,T> = {
//   [P in K] : T
// }

function mapObject<K extends string | number, T, U>(
  obj: Record<K, T>,
  f: (x: T) => U
): Record<K, U> {
  let res: any = {};
  for (const key in obj) {
    res[key] = f(obj[key]);
  }
  return res;
}
const names = { o: 'hello', 1: 'world', 2: 'bye' };
const lengths = mapObject(names, (s) => s.length);
// console.log(lengths)

// 同态 这四个内置的，只有record不是

// 3.2由映射类型进行推断

// 包装
type Proxy<T> = {
  get(): T;
  set(value: T): void;
};
type Proxify<T> = {
  [P in keyof T]: Proxy<T[P]>;
};
function proxify<T>(obj: T): Proxify<T> {
  let result = {} as Proxify<T>;
  for (const key in obj) {
    result[key] = {
      get: () => obj[key],
      set: (value) => (obj[key] = value),
    };
  }
  return result;
}
let props = {
  name: 'lp',
  age: 18,
};
let proxyProps = proxify(props);
// console.log(proxyProps);
// console.log(proxyProps.name.get());
// 拆包
function unproxify<T>(t: Proxify<T>): T {
  const result = {} as T;
  for (const k in t) {
    result[k] = t[k].get();
  }
  return result;
}
let originalProps = unproxify(proxyProps);
// console.log(originalProps);

// 3.3增加或移除特定修饰符
// +
// -

// 3.4keyof和映射类型在2.9的升级

// 映射类型对于属性名为number、string、symbol的支持
const stringIndex = 'a';
const numberIndex = 1;
const symbolIndex = Symbol();
type Objs2 = {
  [stringIndex]: string;
  [numberIndex]: number;
  [symbolIndex]: symbol;
};
type keysType = keyof Objs2;
type ReadonlyTypes<T> = {
  readonly [P in keyof T]: T[P];
};
let objs3: ReadonlyTypes<Objs2> = {
  a: 'aa',
  1: 11,
  [symbolIndex]: Symbol(),
};
// objs3.a = 'bb'
// 3.5元组和数组上的映射类型

// TS在3.1版本中，元组和数组上的映射类型中，会生成新的元组和数组，并不会创建一个新的类型，会具有push、pop等数组属性
type MapToPromise<T> = {
  [K in keyof T]: Promise<T[K]>;
};
type Tuple = [number, string, boolean];
type promiseTuple = MapToPromise<Tuple>;
let tuple1: promiseTuple = [
  new Promise((resolve, reject) => resolve(1)),
  new Promise((resolve, reject) => resolve('a')),
  new Promise((resolve, reject) => resolve(false)),
];

// unknown
// [1] 任何类型都可以赋值给unknown
let value1: unknown;
value1 = 'a';
value1 = 1;
// [2] 如果没有类型断言或基于控制流的类型细化时，unknown不可以赋值给其他类型，此时他只能赋值给unknown和any类型
let value2: unknown;
// let value3:string = value2
value1 = value2;
// [3] 如果没有类型断言或基于控制流的类型细化时，不能在他上面进行任何操作
let value4: unknown;
// value4 += unknown
// [4] unknown与任何其他类型组成的交叉类型，最后都等于其他类型
type type1 = unknown & string;
type type2 = unknown & number;
type type3 = unknown & unknown;
type type4 = unknown & string[];
// [5] unknown与任何其他类型(除了any)组成的联合类型，最后都等于其他类型
type type5 = unknown | string;
type type6 = unknown | any;
type type7 = unknown | number[];
// [6] never类型是unknown的子类型
type type8 = never extends unknown ? true : false;
// [7] keyof unknown 等于类型never
type type9 = keyof unknown;
// [8] 只能对unknown进行等或不等操作，不能进行其他操作
value1 === value2;
// value1+=value2
// [9] unknown类型的值不能访问他的属性、作为函数调用，也不能作为类创建实例
// [10] 使用映射类型如果遍历的是unknown类型，则不会映射任何属性
type Types1<T> = {
  [P in keyof T]: number;
};
type type11 = Types1<any>;
type type12 = Types1<unknown>;

// 4.条件类型
// 4.1基础
// T extends U ? X:Y
type Types2<T> = T extends string ? string : number;
let index: Types2<123>;

// 4.2分布式条件类型
// 当带检测的类型是一个联合类型的时候，该条件类型就被称为分布式条件类型，在实例化时TS会自动分化成联合类型
// type TypeName<T> = T extends any ? T : never;
// type Type3 = TypeName<string | number>;

// 例
type TypeName<T> = T extends string
  ? string
  : T extends number
  ? number
  : T extends boolean
  ? boolean
  : T extends undefined
  ? undefined
  : T extends () => void
  ? () => void
  : object;
type Type4 = TypeName<() => void>;
type Type5 = TypeName<string[]>;
type Type6 = TypeName<(() => void) | string[]>;
// 例
type Diff<T, U> = T extends U ? never : T;
type Test2 = Diff<string | number | boolean, undefined | number>;
// 例
type Type7<T> = {
  [K in keyof T]: T[K] extends Function ? K : never;
}[keyof T];
interface Part {
  id: number;
  name: string;
  subparts: Part[];
  updatePart(newName: string): void;
}
type Test1 = Type7<Part>;

// 4.3条件类型的类型推断-info
// type Type8<T> = T extends any[] ? T[number] : T;
// type Test3 = Type8<string[]>;
// type Test4 = Type8<string>;

// 使用info
type Type9<T> = T extends Array<infer U> ? U : T;
type Test5 = Type9<string[]>;
type Test6 = Type9<string>;

// 4.4TS预定义条件类型
// 2.8版本增加的
// Exclude<T,U> 从前面选出不在后边类型中的
type Type10 = Exclude<'a' | 'b' | 'c', 'a' | 'b'>;

// Extract<T,U> 选取T中可以赋值给U的类型
type Type11 = Extract<'a' | 'b' | 'c', 'c'>;

// NonNullable<T> 去掉T中null和undefined
type Type12 = NonNullable<string | number | null | undefined>;

// ReturnType<T> 获取函数类型返回值类型
type Type13 = ReturnType<() => string>;
type Type14 = ReturnType<() => void>;

// InstanceType<T> 获取构造函数类型的实例类型
class AClass{
  constructor(){}
}
type T1 = InstanceType<typeof AClass>
type T2 = InstanceType<any>
type T3 = InstanceType<never>
// type T4 = InstanceType<string>



